package com.qili.config;

//import com.qili.core.BlogRealm;
//import com.qili.core.MyBasicHttpAuthenticationFilter;

import com.qili.core.filter.MyBasicHttpAuthenticationFilter;
import com.qili.core.filter.PermissionFilter;
import com.qili.core.filter.VerfityCodeFilter;
import com.qili.core.shiro.AppLoginRealm;
import com.qili.core.shiro.LoginRealm;
import com.qili.core.shiro.RetryLimitCredentialsMatcher;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.InvalidRequestFilter;
import org.apache.shiro.web.filter.mgt.DefaultFilter;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.hutool.core.codec.Base64;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.*;

/**
 * @author zhangshuo
 * @date 2021/3/1
 */
@Configuration
public class ShiroConfig {

    @Resource
    private RedisConfig redisConfig;

    /**
    * @Author:Zhangshuo
    * @Description:获取缓存管理器
    * @param
    * @Date:13:59 2021/3/1
    */
    @Bean
    public RedisCacheManager getCacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
    * @Author:Zhangshuo
    * @Description:限制登录次数
    * @param
    * @Date:14:00 2021/3/1
    */
    @Bean
    public RetryLimitCredentialsMatcher getRetryLimitCredentialsMatcher() {
        RetryLimitCredentialsMatcher rm = new RetryLimitCredentialsMatcher(getCacheManager());
        rm.setHashAlgorithmName("md5");
        rm.setHashIterations(4);
        return rm;
    }

    /**
    * @Author:Zhangshuo
    * @Description:获取Realm
    * @param
    * @Date:14:00 2021/3/1
    */
    @Bean(name = "userLoginRealm")
    public LoginRealm getLoginRealm() {
        LoginRealm realm = new LoginRealm();
        realm.setCredentialsMatcher(getRetryLimitCredentialsMatcher());
        return realm;
    }

    /**
    * @Author:Zhangshuo
    * @Description:配置redisManager
    * @param
    * @Date:14:02 2021/3/1
    */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisConfig.getHost());
        redisManager.setTimeout(redisConfig.getTimeout());
        if(StringUtils.isNotBlank(redisConfig.getPassword())){
            redisManager.setPassword(redisConfig.getPassword());
        }
        return redisManager;
    }

    /**
    * @Author:Zhangshuo
    * @Description:配置redisSessionDAO
    * @param
    * @Date:14:02 2021/3/1
    */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
    * @Author:Zhangshuo
    * @Description:session管理
    * @param
    * @Date:14:02 2021/3/1
    */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//        Collection<SessionListener> listeners = new ArrayList<SessionListener>();
//        listeners.add(new MySessionListener());
//        sessionManager.setSessionListeners(listeners);
        //设置session超时时间为1小时(单位毫秒)
        //sessionManager.setGlobalSessionTimeout(3600000);
        //永不超时
        sessionManager.setGlobalSessionTimeout(144000000L);
        //设置redisSessionDao
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
    * @Author:Zhangshuo
    * @Description:权限管理，配置主要是Realm的管理认证
    * @param loginRealm
    * @Date:14:03 2021/3/1
    */
    @Bean(name = "securityManager")
    public SecurityManager getSecurityManager(@Qualifier("userLoginRealm") LoginRealm loginRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //securityManager.setRealm(myShiroRealm());
        loginRealm.setName("UserLogin");
        securityManager.setRealm(loginRealm);
        securityManager.setSessionManager(sessionManager());
        //配置自定义缓存redis
        securityManager.setCacheManager(getCacheManager());
        return securityManager;
    }

    /**
    * @Author:Zhangshuo
    * @Description:
    * @param
    * @Date:14:03 2021/3/1
    */
    @Bean
    public PermissionFilter getPermissionFilter() {
        return new PermissionFilter();
    }

    /**
    * @Author:Zhangshuo
    * @Description:
    * @param
    * @Date:14:03 2021/3/1
    */
    @Bean
    public MyBasicHttpAuthenticationFilter getAuthenticationFilter() {
        return new MyBasicHttpAuthenticationFilter();
    }

    @Bean
    public InvalidRequestFilter getInvalidRequestFilter(){
        InvalidRequestFilter ifr= new InvalidRequestFilter();
        ifr.setBlockNonAscii(false);
        return ifr;
    }

    /**
    * @Author:Zhangshuo
    * @Description:
    * @param
    * @Date:14:03 2021/3/1
    */
    @Bean
    public VerfityCodeFilter getVerfityCodeFilter() {
        VerfityCodeFilter vf = new VerfityCodeFilter();
        vf.setFailureKeyAttribute("shiroLoginFailure");
        vf.setJcaptchaParam("code");
        vf.setVerfitiCode(true);
        return vf;
    }

    /**
    * @Author:Zhangshuo
    * @Description:
    * @param securityManager
    * @Date:14:03 2021/3/1
    */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager) {
        ShiroFilterFactoryBean sfb = new ShiroFilterFactoryBean();

        sfb.setSecurityManager(securityManager);
        sfb.setLoginUrl("/login");
        sfb.setUnauthorizedUrl("/goLogin");

        Map<String, Filter> filters = new HashMap<>();
        filters.put("per", getPermissionFilter());
        filters.put("verCode", getVerfityCodeFilter());
        filters.put("jwt", getAuthenticationFilter());
        filters.put(DefaultFilter.invalidRequest.name(),getInvalidRequestFilter());

        sfb.setFilters(filters);
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/index", "user");
        filterMap.put("/login", "verCode,anon");
        //-----app-----
        filterMap.put("/app/*", "anon");
        filterMap.put("/app/supervisor/*", "anon");
        filterMap.put("/app/zx/*", "anon");
        filterMap.put("/app/jc/*", "anon");
        filterMap.put("/app/gx/*", "anon");
        filterMap.put("/app/lc/*", "anon");
        filterMap.put("/app/exam/*", "anon");

        filterMap.put("/app/dict/*", "anon");
        filterMap.put("/app/version/*", "anon");
        //---app-----
        filterMap.put("/register", "anon");
        filterMap.put("/sys/**", "anon");
        filterMap.put("/blogLogin", "verCode,anon");
        filterMap.put("/getCode", "anon");
        filterMap.put("/app/getCode", "anon");
        //filterMap.put("/app/**", "anon");
        //filterMap.put("/actuator/**", "anon");
        filterMap.put("/img/**", "anon");
        filterMap.put("/imagefiletemp/**", "anon");
        filterMap.put("/itfile/**", "anon");
        filterMap.put("/logout", "logout");
        filterMap.put("/plugin/**", "anon");
        filterMap.put("/user/**", "per");
        filterMap.put("/blog/**", "anon");
        filterMap.put("/userfile/**", "anon");
        filterMap.put("/Word/**", "anon");
        filterMap.put("/download/**", "anon");
        filterMap.put("/**", "user");
        sfb.setFilterChainDefinitionMap(filterMap);
        return sfb;
    }
    /**
    * @Author:Zhangshuo
    * @Description:
    * @param
    * @Date:14:03 2021/3/1
    */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
    * @Author:Zhangshuo
    * @Description:
    * @param securityManager
    * @Date:14:03 2021/3/1
    */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor as = new AuthorizationAttributeSourceAdvisor();
        as.setSecurityManager(securityManager);
        return as;
    }

//    @Bean
//    public DefaultWebSessionManager defaultWebSessionManager() {
//        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
//        defaultWebSessionManager.setSessionIdCookieEnabled(true);
//        defaultWebSessionManager.setGlobalSessionTimeout(21600000);
//        defaultWebSessionManager.setDeleteInvalidSessions(true);
//        defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
//        defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false);
//        return defaultWebSessionManager;
//    }

    /**
    * @Author:Zhangshuo
    * @Description:cookie对象
    * @param
    * @Date:14:04 2021/3/1
    */
    public SimpleCookie rememberMeCookie() {
        // 设置cookie名称，对应login.html页面的<input type="checkbox" name="rememberMe"/>
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        // 设置cookie的过期时间，单位为秒，这里为一天
        cookie.setMaxAge(86400);
        return cookie;
    }

    /**
    * @Author:Zhangshuo
    * @Description:cookie管理对象
    * @param
    * @Date:14:04 2021/3/1
    */
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
/*        cookieRememberMeManager.setCookie(rememberMeCookie());
        // rememberMe cookie加密的密钥
        cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));*/
        return cookieRememberMeManager;
    }

    /**
    * @Author:Zhangshuo
    * @Description:cookie管理对象
    * @param
    * @Date:14:04 2021/3/1
    */
    @Bean
    public FilterRegistrationBean delegatingFilterProxy(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");

        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }
}
